from django.conf import settings
from django.db.models import F
from django.http import HttpResponseBadRequest, JsonResponse
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse

# Create your views here.
# 使用类视图渲染页面
from django.views.generic import ListView, TemplateView, DetailView

from blog.forms import CommentForm
from blog.models import Article, Page, Category, Comment


# 展示首页
class IndexView(TemplateView):
    """
    用于渲染首页的视图
    """
    template_name = 'index.html'


class SinglePageView(TemplateView):
    # 指定模板名称
    template_name = 'page.html'
    # 指定模型，确保 'Page' 是相应的模型名称
    model = Page

    def get_context_data(self, **kwargs):
        """
        获取上下文数据，在原有基础上添加页面对象。
        """
        # 调用父类方法获取基础上下文数据
        context = super().get_context_data(**kwargs)
        # 通过get_object方法获取对象，这样做可以避免直接查询，提高代码复用性和可维护性
        context['page'] = self.get_object()
        return context

    def get_object(self):
        """
        获取特定的页面对象。
        通过URL中的'slug'参数来获取特定的页面对象，如果对象不存在，则返回404错误。
        """
        # 从URL参数中获取'slug'值
        slug = self.kwargs.get('slug')
        # 使用快捷方式获取对象或返回404错误，这样可以避免NoneType错误，并确保返回有效的页面对象
        return get_object_or_404(self.model, slug=slug)


# 创建一个列表视图
class ArticleListView(ListView):
    """
    用于渲染文章列表的视图
    """
    # 指定模板名称
    template_name = 'list.html'
    # 指定模型，确保 'Article' 是相应的模型名称
    model = Article
    # 指定上下文对象的名称
    context_object_name = 'article_list'
    # 指定每页显示的文章数量
    paginate_by = settings.PAGE_SIZE
    # 指定排序方式
    ordering = '-created_at'

    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(status=True)


# 创建一个详情视图
class ArticleDetailView(DetailView):
    template_name = 'article.html'
    model = Article
    context_object_name = 'article'
    queryset = Article.objects.select_related('category')

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        self.object.click_count = F('click_count') + 1
        self.object.save(update_fields=['click_count'])
        self.object.refresh_from_db()
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        article = context['article']

        try:
            context['prev_article'] = article.get_previous_by_created_at()
        except Article.DoesNotExist:
            context['prev_article'] = None

        try:
            context['next_article'] = article.get_next_by_created_at()
        except Article.DoesNotExist:
            context['next_article'] = None

        context['comment_form'] = CommentForm()
        # 获取文章的顶级评论（即父级评论为空的评论）
        context['comments'] = article.comments.filter(comment_parent__isnull=True).order_by('-created_at')
        # 计算文章的评论数,包括回复
        context['comment_count'] = article.comments.count()

        return context

    def post(self, request, *args, **kwargs):
        """
        处理POST请求，用于提交评论。

        参数：
        - request: HttpRequest对象，包含请求的数据。
        - *args: 可变参数，用于传递额外的非关键字参数。
        - **kwargs: 关键字参数，用于传递额外的键值对参数。

        返回：
        - 如果评论表单数据有效，则保存评论并重定向到文章详情页。
        - 如果评论表单数据无效，则重新渲染页面，显示带有错误信息的表单。
        """
        # 获取要评论的文章对象
        self.object = self.get_object()
        # 初始化一个评论表单，传入POST请求数据
        form = CommentForm(request.POST)
        # 验证表单数据是否合法
        if form.is_valid():
            # 保存评论，但暂时不提交到数据库
            comment = form.save(commit=False)
            # 将评论关联到指定的文章
            comment.article = self.object
            # 最终将评论保存到数据库
            comment.save()
            # 重定向到文章详情页
            return redirect(self.object)

        # 获取页面的上下文数据
        context = self.get_context_data(object=self.object)
        # 将评论表单添加到上下文中，以便在页面上显示
        context['comment_form'] = form
        # 使用指定的上下文数据渲染页面并返回响应
        return self.render_to_response(context)


# 通过分类展示文章
class CategoryArticleListView(ListView):
    """
    用于通过分类展示文章列表的视图
    """
    # 指定模板名称
    template_name = 'list.html'
    # 指定模型，确保 'Article' 是相应的模型名称
    model = Article
    # 指定上下文对象的名称
    context_object_name = 'article_list'
    # 指定每页显示的文章数量
    paginate_by = settings.PAGE_SIZE
    # 指定排序方式
    ordering = '-created_at'

    def get_queryset(self):
        queryset = super().get_queryset()
        # 从URL参数中获取分类ID
        category_id = self.kwargs.get('pk')
        return queryset.filter(category_id=category_id, status=True)

    def get_context_data(self, **kwargs):
        """
        获取上下文数据，在原有基础上添加分类对象。
        :param kwargs:  关键字参数
        :return:  上下文数据
        """
        context = super().get_context_data(**kwargs)
        category_id = self.kwargs.get('pk')
        context['category'] = get_object_or_404(Category, pk=category_id)
        return context
